package com.lightbend.akka.sample

import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, Behavior, PostStop, Signal}
import com.lightbend.akka.sample.DeviceManager.{DeviceGroupTerminated, ReplyDeviceList, RequestDeviceList, RequestTrackDevice}

object DeviceManager{
  def apply(): Behavior[Command] = Behaviors.setup(context => new DeviceManager(context))
  sealed trait Command

  final case class RequestTrackDevice(groupId: String, deviceId:String, replyTo: ActorRef[DeviceRegistered]) extends DeviceManager.Command with DeviceGroup.Command

  final case class DeviceRegistered(device: ActorRef[Device.Command])

  final case class RequestDeviceList(requestId:Long, groupId: String, replyTo:ActorRef[ReplyDeviceList]) extends DeviceManager.Command with DeviceGroup.Command

  final case class ReplyDeviceList(requestId: Long, ids: Set[String])

  private final case class DeviceGroupTerminated(groupId: String) extends DeviceManager.Command

}
class DeviceManager(context:ActorContext[DeviceManager.Command]) extends AbstractBehavior[DeviceManager.Command](context = context) {
  var groupIdToActor = Map.empty[String, ActorRef[DeviceGroup.Command]]

  context.log.info("DeviceManager started")

  override def onMessage(msg: DeviceManager.Command): Behavior[DeviceManager.Command] = {
    msg match {
      case trackMsg @ RequestTrackDevice(groupId, _, replyTo) =>
        groupIdToActor.get(groupId) match {
          case Some(ref) =>
            ref ! trackMsg
          case None =>
            context.log.info("Creating device group actor for {}", groupId)
            val groupActor = context.spawn(DeviceGroup(groupId), s"group-$groupId")
            context.watchWith(groupActor, DeviceGroupTerminated(groupId))
            groupActor ! trackMsg
            groupIdToActor += groupId -> groupActor
        }
        this

      case req @ RequestDeviceList(requestId, groupId, replyTo) =>
        groupIdToActor.get(groupId) match {
          case Some(ref) =>
            ref ! req
          case None =>
            replyTo ! ReplyDeviceList(requestId, Set.empty)
        }
        this
      case DeviceGroupTerminated(groupId) =>
        context.log.info("Device group actor for {} has been terminated", groupId)
        groupIdToActor -= groupId
        this
    }
  }



  override def onSignal: PartialFunction[Signal, Behavior[DeviceManager.Command]] = {
    case stop: PostStop =>
      context.log.info("DeviceManager stopped")
      this
  }
}

